#pragma once
#include<string>
#include<unistd.h>
#include <fcntl.h>
#include"../Comm/Util.hpp"
#include"../Comm/Log.hpp"
#include <sys/stat.h>
#include <sys/wait.h>
#include<iostream>
namespace Compile_ns
{
    using namespace util_ns;
    using namespace Log_ns;
    class Compiler
    {
        public:
            Compiler()
            {}
            ~Compiler()
            {}
            
            
            static bool Compile(const std::string& filename)
            {
                pid_t pid  = fork();
                
                if(pid < 0)
                {
                    //打印错误信息
                    LOG(ERROR) << "内部错误，进程创建失败" << "\n";
                    return false;
                }

                else  if(pid == 0)
                {
                    //子进程
                    //新建一个文件，用来存编译时的错误信息（如果有）
                    umask(0);
                    int _stderr = open(Path_Util::Compile_Error_Path(filename).c_str(),O_CREAT | O_WRONLY,0644);

                    if(_stderr < 0)
                    {
                        //文件打开失败了，无法继续执行
                        LOG(WARNNING) << "Compile_Error file 创建失败" << "\n";
                        exit(1);
                    }

                    //重定向标准错误流，让它将内容写到我们的文件中
                    dup2(_stderr,2);

                    //可以开始执行源代码了
                    //g++ -o target src -std-c++11
                    execlp("g++","g++","-o",Path_Util::Exe_Path(filename).c_str(),Path_Util::Src_Path(filename).c_str(),"-std=c++11","-D","COMPILER_ONLINE",nullptr);

                    //内部错误
                    LOG(ERROR) << "启动编译器失败，可能是参数传错了" << "\n";
                    exit(2);
                }

                else if(pid > 0)
                {
                    //父进程
                    waitpid(pid,nullptr,0);//阻塞式的等待子进程编译完代码

                    //判断是否编译成功，就看exe文件是否生成了
                    if(!File_Util::Is_Exist_File(Path_Util::Exe_Path(filename)))//编译失败
                    {
                        LOG(ERROR) << "编译失败，没有形成可执行文件" << "\n";
                        return false;
                    }
                }
                //走到这里一定编译成功了
                LOG(INFO) << "编译成功" << "\n";
                return true;
            }
    };
};